package io.gitee.javalaoniu.mpgen.genarator;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import io.gitee.javalaoniu.mpgen.genarator.util.ImageUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * mysql 代码生成器
 * </p>
 *
 * @author javalaoniu
 */
@Mojo(name = "generate", requiresProject = false)
public class MybatisPlusGenerator extends AbstractMojo {
    @Parameter(property = "author", defaultValue = "")
    private String author;
    @Parameter(property = "savePath")
    private String savePath;
    @Parameter(property = "projectName")
    private String projectName;
    /**
     * 直接使用maven的属性
     */
    @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true)
    private String targetDirectory;
    @Parameter(property = "fileOverride", defaultValue = "false", required = true)
    private boolean fileOverride;
    @Parameter(property = "openApi3", defaultValue = "false")
    private boolean openApi3;
    @Parameter
    private DbSetting dbSetting;
    @Parameter
    private PackageSetting packageSetting;
    @Parameter
    private StrategySetting strategySetting;

    public static void main(String[] args) throws MojoExecutionException {
        DbSetting myDbSetting = new DbSetting();
        myDbSetting.setType("mysql");
        myDbSetting.setUrl(
                "jdbc:mysql://127.0.0.1:3306/erp2024?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&tinyInt1isBit=false&allowMultiQueries=true");
        myDbSetting.setUsername("root");
        myDbSetting.setPwd("root123456");
        myDbSetting.setDriverClass("com.mysql.cj.jdbc.Driver");
        //myDbSetting.setSchema();
        myDbSetting.setTablePrefix("t_");
        //myDbSetting.setTables("sys_user, t_table2, t_table3");
        myDbSetting.setTables("sys_user,bom,bom_cost,bom_list,material,material_cost,material_snapshoot,material_type,purchase_order,purchase_order_detail,purchase_plan,purchase_plan_detail,stock,store,supplier,sys_dept.sys_menu,sys_user");


        PackageSetting myPackageSetting = new PackageSetting();
        myPackageSetting.setParent("com");
        myPackageSetting.setEntity("model");
        myPackageSetting.setMapper("mapper");
        myPackageSetting.setService("service");
        myPackageSetting.setServiceImpl("service.impl");
        myPackageSetting.setController("controller");
        myPackageSetting.setXml("mapper");


        StrategySetting myStrategySetting = new StrategySetting();

        String outputDir = "D:\\mympdemo";

        String author = "zhang3";

        String projectName = "demo1";
        boolean fileOverride = true;
        boolean swagger3 = true;

        MybatisPlusGenerator mybatisPlusGenerator = new MybatisPlusGenerator();
        mybatisPlusGenerator.generate(myDbSetting, myPackageSetting, myStrategySetting, outputDir, projectName, fileOverride,
                                      swagger3, author);
    }

    /**
     * 运行main函数生成代码
     */
    @Override
    public void execute() throws MojoExecutionException {
        this.getLog().info("=======================开始生成代码======================");
        validateRequired();

        String outputDir = getSavePath();
        DbSetting myDbSetting = getDbSetting();
        PackageSetting myPackageSetting = getPackageSetting();
        StrategySetting myStrategySetting = getStrategySetting();

        String module = this.projectName;

        generate(myDbSetting, myPackageSetting, myStrategySetting, outputDir, module, fileOverride, openApi3, author);

        this.getLog().info("=====================生成代码完成=====================");
        this.getLog().info("==== output path: " + outputDir);
    }

    private void generate(DbSetting myDbSetting, PackageSetting myPackageSetting, StrategySetting myStrategySetting,
            String outputDir, String module, boolean fileOverride, boolean swagger3,
            String author) throws MojoExecutionException {

        String projectDir = outputDir + File.separator + module;

        String srcJavaDir = projectDir + File.separator + "src" + File.separator + "main" + File.separator + "java";

        String srcResourcesDir =
                projectDir + File.separator + "src" + File.separator + "main" + File.separator + "resources";

        String moduleDirTmp = srcJavaDir + File.separator + module;
        String modulePackageTmp = module;
        if (myPackageSetting.getParent().length() > 0) {
            moduleDirTmp =
                    srcJavaDir + File.separator + myPackageSetting.getParent().replace(StringPool.DOT, File.separator) +
                            File.separator + module;

            modulePackageTmp = myPackageSetting.getParent() + StringPool.DOT + module;
        }

        String moduleDir = moduleDirTmp;
        String modulePackage = modulePackageTmp;

        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        // java代码的输出路径
        gc.setOutputDir(srcJavaDir);
        gc.setAuthor(author);
        gc.setFileOverride(fileOverride);
        /*
            AUTO 数据库ID自增
            INPUT 用户输入ID
            ID_WORKER 全局唯一ID，Long类型的主键
            ID_WORKER_STR 字符串全局唯一ID
            UUID 全局唯一ID，UUID类型的主键
            NONE 该类型为未设置主键类型
         */
        gc.setIdType(IdType.AUTO);
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        gc.setOpen(false);
        gc.setSwagger2(swagger3);
        gc.setActiveRecord(true);
        //新语言模式
        gc.setKotlin(false);
        //Service的命名
        gc.setServiceName("%sService");
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        DbType dbType = DbType.getDbType(myDbSetting.getType());
        dsc.setDbType(dbType);
        dsc.setUrl(myDbSetting.getUrl());
        if (myDbSetting.getSchema() != null && myDbSetting.getSchema().trim().length() > 0) {
            dsc.setSchemaName(myDbSetting.getSchema());
        }
        dsc.setDriverName(myDbSetting.getDriverClass());
        dsc.setUsername(myDbSetting.getUsername());
        dsc.setPassword(myDbSetting.getPwd());
        mpg.setDataSource(dsc);

        // 包配置参数
        PackageConfig pc = new PackageConfig();
        pc.setParent(myPackageSetting.getParent());
        pc.setModuleName(module);
        // 把数据库的表对应的实体放入到po包中，个人喜欢
        pc.setEntity(myPackageSetting.getEntity() + ".po");
        pc.setController(myPackageSetting.getController());
        pc.setMapper(myPackageSetting.getMapper());
        pc.setService(myPackageSetting.getService());
        pc.setServiceImpl(myPackageSetting.getServiceImpl());
        mpg.setPackageInfo(pc);

        // 自定义文件的保存路径和文件的包名
        String nowDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));
        String utilsFolderName = "utils";
        String utilsPackageName = "utils";

        String configFolderName = "config";
        String configPackageName = "config";

        String constsFolderName = "consts";
        String constsPackageName = "consts";

        String exceptionFolderName = "exception";
        String exceptionPackageName = "exception";

        String aopFolderName = "aop";
        String aopPackageName = "aop";

        String controllerFolderName = myPackageSetting.getController().replace(StringPool.DOT, File.separator);
        String entityFolderName = myPackageSetting.getEntity().replace(StringPool.DOT, File.separator);

        String entityVoFolderName = entityFolderName + File.separator + "vo";
        String entityVoPackageName = myPackageSetting.getEntity() + StringPool.DOT + "vo";

        String entityCommonFolderName = entityFolderName + File.separator + "common";
        String entityCommonPackageName = myPackageSetting.getEntity() + StringPool.DOT + "common";


        // 自定义配置参数，自定义参数也可以用于全局
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                map.put("module", module);
                map.put("appPackage", modulePackage);
                map.put("voEntityPackage", modulePackage + StringPool.DOT + entityVoPackageName);
                map.put("commonPackage", modulePackage + StringPool.DOT + entityCommonPackageName);
                map.put("utilPackage", modulePackage + StringPool.DOT + utilsPackageName);
                map.put("configPackage", modulePackage + StringPool.DOT + configPackageName);
                map.put("constsPackage", modulePackage + StringPool.DOT + constsPackageName);
                map.put("exceptionPackage", modulePackage + StringPool.DOT + exceptionPackageName);
                map.put("aopPackage", modulePackage + StringPool.DOT + aopPackageName);
                map.put("jdbcUrl", myDbSetting.getUrl());
                map.put("jdbcUser", myDbSetting.getUsername());
                map.put("jdbcPwd", myDbSetting.getPwd());
                map.put("dbType", "DbType." + dbType.name());
                map.put("createTime", nowDateTime);
                map.put("requestMappingUrlPrefix", "/api/v1/test");
                map.put("swagger3", swagger3);
                this.setMap(map);
            }
        };

        // 设置自定义配置列表
        // 自定义输出配置列表
        List<FileOutConfig> focList = new ArrayList<>();

        /*
         默认mybatis-plus-generator的包下面有以下模板，可以根据自己需要重写
         controller.java.ftl
         service.java.ftl
         serviceImpl.java.ftl
         entity.java.ftl
         mapper.java.ftl
         mapper.xml.ftl
         其他模板引擎的：
         ...java.btl
         ...java.vm
         */

        // 添加自定义项
        focList.add(new FileOutConfig("/templates/AppApplication.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + "AppApplication.java";
            }
        });

        focList.add(new FileOutConfig("/templates/entityVO.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + entityVoFolderName + File.separator + tableInfo.getEntityName() +
                        "VO" + StringPool.DOT_JAVA;
            }
        });

        focList.add(new FileOutConfig("/templates/AppResp.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + entityCommonFolderName + File.separator + "AppResp.java";
            }
        });
        focList.add(new FileOutConfig("/templates/PageParams.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + entityCommonFolderName + File.separator + "PageParams.java";
            }
        });
        focList.add(new FileOutConfig("/templates/PageResult.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + entityCommonFolderName + File.separator + "PageResult.java";
            }
        });

        focList.add(new FileOutConfig("/templates/OrikaBeanMapper.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + utilsFolderName + File.separator + "OrikaBeanMapper.java";
            }
        });
        focList.add(new FileOutConfig("/templates/QueryWrapperHelper.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + utilsFolderName + File.separator + "QueryWrapperHelper.java";
            }
        });
        focList.add(new FileOutConfig("/templates/BeanUtil.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + utilsFolderName + File.separator + "BeanUtil.java";
            }
        });
        focList.add(new FileOutConfig("/templates/SpringContextUtil.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + utilsFolderName + File.separator + "SpringContextUtil.java";
            }
        });

        focList.add(new FileOutConfig("/templates/MybatisPlusConfig.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + configFolderName + File.separator + "MybatisPlusConfig.java";
            }
        });
        /*
        // swagger3（knife4j-openapi3-jakarta-spring-boot-starter）在yml中配置就可以了
        focList.add(new FileOutConfig("/templates/SwaggerConfig.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator
                        + configFolderName + File.separator + "SwaggerConfig.java";
            }
        });*/
        focList.add(new FileOutConfig("/templates/GlobalExceptionAdvice.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + aopFolderName + File.separator + "GlobalExceptionAdvice.java";
            }
        });
        focList.add(new FileOutConfig("/templates/AppException.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + exceptionFolderName + File.separator + "AppException.java";
            }
        });

        focList.add(new FileOutConfig("/templates/AppErrorCode.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + constsFolderName + File.separator + "AppErrorCode.java";
            }
        });

        focList.add(new FileOutConfig("/templates/TestController.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return moduleDir + File.separator + controllerFolderName + File.separator + "TestController.java";
            }
        });

        focList.add(new FileOutConfig("/templates/application.yml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return srcResourcesDir + File.separator + "application.yml";
            }
        });
        focList.add(new FileOutConfig("/templates/application-dev.yml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return srcResourcesDir + File.separator + "application-dev.yml";
            }
        });
        focList.add(new FileOutConfig("/templates/application-prod.yml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return srcResourcesDir + File.separator + "application-prod.yml";
            }
        });
        focList.add(new FileOutConfig("/templates/application.mp.yml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return srcResourcesDir + File.separator + "application-mp.yml";
            }
        });
        focList.add(new FileOutConfig("/templates/logback-spring.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return srcResourcesDir + File.separator + "logback-spring.xml";
            }
        });
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return srcResourcesDir + File.separator +
                        myPackageSetting.getXml().replace(StringPool.DOT, File.separator) + File.separator +
                        tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        focList.add(new FileOutConfig("/templates/README.md.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return projectDir + File.separator + "README.md";
            }
        });
        focList.add(new FileOutConfig("/templates/git.gitignore.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return projectDir + File.separator + ".gitignore";
            }
        });
        focList.add(new FileOutConfig("/templates/pom.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义文件输入路径
                return projectDir + File.separator + "pom.xml";
            }
        });


        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);


        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        // 配置自定义输出模板，如果设置为null并且focList中没有自定义输出则不会生成相应的文件。
        // 指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // xml使用下面自定义的
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(false);
        strategy.setRestControllerStyle(true);

        if (myStrategySetting != null) {
            // 公共父类
            if (myStrategySetting.getEntitySuperClass() != null &&
                    myStrategySetting.getEntitySuperClass().trim().length() > 0) {
                strategy.setSuperEntityClass(myStrategySetting.getEntitySuperClass());
            }
            if (myStrategySetting.getControllerSuperClass() != null &&
                    myStrategySetting.getControllerSuperClass().trim().length() > 0) {
                strategy.setSuperControllerClass(myStrategySetting.getControllerSuperClass());
            }
        }


        // 设置前缀
        strategy.setInclude(myDbSetting.getTables().split(","));
        strategy.setControllerMappingHyphenStyle(true);
        if (myDbSetting.getTablePrefix() != null && myDbSetting.getTablePrefix().trim().length() > 0) {
            strategy.setTablePrefix(myDbSetting.getTablePrefix());
        }
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();

        this.getLog().info("项目文件生成完成！ 拷贝其他文件...");
        try {
            // 完成之后拷贝其他文件
            copyFile("/imgs/img_q1.png", projectDir + File.separator + "imgs" + File.separator + "img_q1.png");

            // 生成一个logo
            genIco(module, srcResourcesDir);
        } catch (Exception e) {
            throw new MojoExecutionException("文件拷贝异常：", e.getCause());
        }


    }

    private void copyFile(String source, String desc) throws IOException {
        File file = new File(desc);
        this.getLog().info("拷贝[" + source + "]文件到[" + file.getAbsoluteFile() + "]");
        if (!file.exists()) {
            file.mkdirs();
            file.createNewFile();
        }
        Files.copy(Objects.requireNonNull(this.getClass().getResourceAsStream(source)), file.toPath(),
                   StandardCopyOption.REPLACE_EXISTING);
    }

    private void genIco(String moduleName, String srcResourcesDir) throws IOException {
        // 生成一个logo
        String icoPath = srcResourcesDir + File.separator + "static";
        String ico = icoPath + File.separator + "favicon.ico";
        File file = new File(icoPath);
        this.getLog().info("生成[favicon.ico]文件到[" + ico + "]");
        if (!file.exists()) {
            file.mkdirs();
        }

        ImageUtils.genIco(moduleName, ico);
    }

    private void validateRequired() throws MojoExecutionException {
        if (this.projectName == null || this.projectName.trim().length() == 0) {
            throw new MojoExecutionException(
                    "请在configuration中配置项目名称[projectName], example: 'demo1', 当配置模块名为demo1时，包名前部分为'com.china.demo1'");
        }

        String packagePattern = "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*[0-9a-z_]$";
        if (!this.projectName.matches(packagePattern)) {
            throw new MojoExecutionException("项目名称当作包名的一部分，所以需要必须是[a-z0-9_]中的字符组成，并且是字母开头");
        }

    }

    private String getSavePath() throws MojoExecutionException {
        if (this.savePath != null && this.savePath.trim().length() > 0) {
            return this.savePath;
        }
        this.getLog().info("在configuration中没有配置保存路径[savePath], 将把生成文件保存在在当前项目的'target'目录");
        return targetDirectory + File.separator + "mybatis-code";
    }

    private DbSetting getDbSetting() throws MojoExecutionException {
        DbSetting dbSetting = this.dbSetting;
        if (dbSetting == null) {
            dbSetting = new DbSetting();
        }
        if (dbSetting.getType() == null || dbSetting.getType().trim().length() == 0) {
            this.getLog().info("在dbSetting中没有配置数据库类型[type], 默认设置为：mysql");
            dbSetting.setType("mysql");
        }
        if (dbSetting.getUrl() == null || dbSetting.getUrl().trim().length() == 0) {
            throw new MojoExecutionException("请在dbSetting中配置数据库地址[url]");
        }
        if (dbSetting.getUsername() == null || dbSetting.getUsername().trim().length() == 0) {
            throw new MojoExecutionException("请在dbSetting中配置数据库用户名[username]");
        }
        if (dbSetting.getPwd() == null || dbSetting.getPwd().trim().length() == 0) {
            throw new MojoExecutionException("请在dbSetting中配置数据库密码[pwd]");
        }
        if (dbSetting.getDriverClass() == null || dbSetting.getDriverClass().trim().length() == 0) {
            this.getLog().info("在dbSetting中没有配置数据库驱动[driverClass]，默认设置为：com.mysql.cj.jdbc.Driver");
            dbSetting.setDriverClass("com.mysql.cj.jdbc.Driver");
        }
        if (dbSetting.getSchema() == null || dbSetting.getSchema().trim().length() == 0) {
            this.getLog().info("在dbSetting中没有配置[schema]，默认为空");
        }
        if (dbSetting.getTablePrefix() == null || dbSetting.getTablePrefix().trim().length() == 0) {
            this.getLog().info("在dbSetting中没有配置[tablePrefix]，默认为空");
        }
        if (dbSetting.getTables() == null || dbSetting.getTables().trim().length() == 0) {
            throw new MojoExecutionException("请在dbSetting中配置表名[tables]");
        }
        return dbSetting;
    }

    private PackageSetting getPackageSetting() throws MojoExecutionException {
        PackageSetting packageSetting = this.packageSetting;
        if (packageSetting == null) {
            packageSetting = new PackageSetting();
        }

        PackageConfig defaultPackageConfig = new PackageConfig();

        String packagePattern = "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*[0-9a-z_]$";
        if (packageSetting.getParent() == null || packageSetting.getParent().trim().length() == 0) {
            this.getLog().info("在packageSetting中没有设置父包名[parent]，默认为: "+defaultPackageConfig.getParent());
            packageSetting.setParent(defaultPackageConfig.getParent());
        }
        if (packageSetting.getController() == null || packageSetting.getController().trim().length() == 0) {
            this.getLog().info("在packageSetting中没有设置[controller]，默认为: "+defaultPackageConfig.getController());
            packageSetting.setController(defaultPackageConfig.getController());
        }
        if (packageSetting.getService() == null || packageSetting.getService().trim().length() == 0) {
            this.getLog().info("在packageSetting中没有设置[service]，默认为: "+defaultPackageConfig.getService());
            packageSetting.setService(defaultPackageConfig.getService());
        }
        if (packageSetting.getServiceImpl() == null || packageSetting.getServiceImpl().trim().length() == 0) {
            this.getLog().info("在packageSetting中没有设置[serviceImpl]，默认为: "+defaultPackageConfig.getServiceImpl());
            packageSetting.setServiceImpl(defaultPackageConfig.getServiceImpl());
        }
        if (packageSetting.getMapper() == null || packageSetting.getMapper().trim().length() == 0) {
            this.getLog().info("在packageSetting中没有设置[mapper]，默认为: "+defaultPackageConfig.getMapper());
            packageSetting.setMapper(defaultPackageConfig.getMapper());
        }
        if (packageSetting.getXml() == null || packageSetting.getXml().trim().length() == 0) {
            this.getLog().info("在packageSetting中没有设置[xml]，默认为: "+defaultPackageConfig.getXml());
            packageSetting.setXml(defaultPackageConfig.getXml());
        }
        if (packageSetting.getEntity() == null || packageSetting.getEntity().trim().length() == 0) {
            this.getLog().info("在packageSetting中没有设置[entity]，默认为: "+defaultPackageConfig.getEntity());
            packageSetting.setEntity(defaultPackageConfig.getEntity());
        }

        if (!packageSetting.getParent().matches(packagePattern) ||
                !packageSetting.getController().matches(packagePattern) ||
                !packageSetting.getService().matches(packagePattern) ||
                !packageSetting.getServiceImpl().matches(packagePattern) ||
                !packageSetting.getMapper().matches(packagePattern) ||
                !packageSetting.getEntity().matches(packagePattern) ||
                !packageSetting.getXml().matches(packagePattern)) {
            throw new MojoExecutionException("包配置下的所有属性配置只能是[a-z0-9_.]中的字符组成，且必须为字符开头");
        }

        return packageSetting;
    }

    private StrategySetting getStrategySetting() {
        StrategySetting strategySetting = this.strategySetting;
        if (strategySetting == null) {
            strategySetting = new StrategySetting();
        }
        if (strategySetting.getControllerSuperClass() == null ||
                strategySetting.getControllerSuperClass().trim().length() == 0) {
            this.getLog().info("在strategySetting中没有配置[controllerSuperClass]，默认为空");
        }
        if (strategySetting.getEntitySuperClass() == null ||
                strategySetting.getEntitySuperClass().trim().length() == 0) {
            this.getLog().info("在strategySetting中没有配置[entitySuperClass]，默认为空");
        }
        return strategySetting;
    }

    /**
     * 数据库配置
     */
    public static class DbSetting {
        private String type;
        private String url;
        private String username;
        private String pwd;
        private String driverClass;
        private String schema;
        private String tablePrefix;
        private String tables;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPwd() {
            return pwd;
        }

        public void setPwd(String pwd) {
            this.pwd = pwd;
        }

        public String getDriverClass() {
            return driverClass;
        }

        public void setDriverClass(String driverClass) {
            this.driverClass = driverClass;
        }

        public String getSchema() {
            return schema;
        }

        public void setSchema(String schema) {
            this.schema = schema;
        }

        public String getTablePrefix() {
            return tablePrefix;
        }

        public void setTablePrefix(String tablePrefix) {
            this.tablePrefix = tablePrefix;
        }

        public String getTables() {
            return tables;
        }

        public void setTables(String tables) {
            this.tables = tables;
        }
    }

    public static class StrategySetting {
        private String entitySuperClass;
        private String controllerSuperClass;

        public String getEntitySuperClass() {
            return entitySuperClass;
        }

        public void setEntitySuperClass(String entitySuperClass) {
            this.entitySuperClass = entitySuperClass;
        }

        public String getControllerSuperClass() {
            return controllerSuperClass;
        }

        public void setControllerSuperClass(String controllerSuperClass) {
            this.controllerSuperClass = controllerSuperClass;
        }
    }

    public static class PackageSetting {
        /**
         * 父包名。如果为空，将下面子包名必须写全部， 否则就只需写子包名
         */
        private String parent;
        /**
         * 包名配置，entity实体类的包名。例如“com.example.model.po”
         */
        private String entity;
        private String mapper;
        private String service;
        private String serviceImpl;
        private String controller;
        private String xml;

        public String getParent() {
            return parent;
        }

        public void setParent(String parent) {
            this.parent = parent;
        }

        public String getEntity() {
            return entity;
        }

        public void setEntity(String entity) {
            this.entity = entity;
        }

        public String getMapper() {
            return mapper;
        }

        public void setMapper(String mapper) {
            this.mapper = mapper;
        }

        public String getService() {
            return service;
        }

        public void setService(String service) {
            this.service = service;
        }

        public String getServiceImpl() {
            return serviceImpl;
        }

        public void setServiceImpl(String serviceImpl) {
            this.serviceImpl = serviceImpl;
        }

        public String getController() {
            return controller;
        }

        public void setController(String controller) {
            this.controller = controller;
        }

        public String getXml() {
            return xml;
        }

        public void setXml(String xml) {
            this.xml = xml;
        }
    }


}
